
#ifndef _XGBA_H_
#define _XGBA_H_

#include <stdint.h>

/*

*/

typedef struct xgba_t xgba_t;
typedef int (*xgba_tile_render_func_t)(xgba_t*gba,uint32_t *screen_line);
typedef uint8_t obj_render_data_t[0x100];
typedef int mem_cycles_t[4];

typedef struct xgba_t{
    uint32_t    R[0x200];  //寄存器
    uint8_t     bios[0x4000];
    uint8_t     wram[0x40000];
    uint8_t     iram[0x8000];
    uint8_t     pal[0x400];
    uint8_t     vram[0x18000];
    uint8_t     oam[0x400];
    uint8_t     sram[0x10000];
    uint8_t     io[0x400];
    uint8_t     wio[0x10];
    uint8_t     nullmem[0x10];
    uint8_t     *rom;
    void        (*rom_free)(void*data);

    uint8_t     *mem_map[0x100];         //内存布局
    uint32_t    mem_map_mask[0x100];    //位置掩码
    uint8_t     *w_mem_map[0x100];        //写入指令的内存布局
    uint32_t    w_mem_map_mask[0x100];    //写入指令的位置掩码

    #if 0
    int         **read_cycles;
    int         **write_cycles;
    #else
    mem_cycles_t    read_cycles[0x10];
    mem_cycles_t    write_cycles[0x10];
    // mem_cycles_t    exec_cycles_first[0x10];
    // mem_cycles_t    exec_cycles_second[0x10];
    mem_cycles_t    exec_cycles[0x20];
    mem_cycles_t    exec_cycles32[0x20];
    int             exec_next;
    #endif
    uint32_t    tilePal[0x200];
    int         screen_line;
    xgba_tile_render_func_t
                tile_render[0x100];
    xgba_tile_render_func_t
                tile_render_blend[0x100];
    obj_render_data_t
                obj_render[4];      //对应tile_render
    uint32_t    obj_prio[0x100];    //以4bit为目标
    uint32_t    **screen;

    void *render_data;
    int (*render)(xgba_t*gba);
    void *error_data;
    int (*errorf)(void*error,const char*fmt,...);
}xgba_t;


/*
16.78MHz

实际上每个绘制屏幕一个点，需要4个CPU时钟.
每行需要绘制308点,其中240点是屏幕内的,68点是水平中断时钟
绘制一行,需要308 * 4 = 1232 CPU时钟

每帧需要渲染228行,其中160行是屏幕时间,68是垂直中断时间
绘制每一帧需要 228 * 1232 = 280896 CPU时钟

则一秒，刷新次数为 (16*1024*1024)/280896 = 59.7275

*/
#define GBA_CPU_CLOCK (16*1024*1024)
#define NS (1000000000)
enum{
    per_clock_ns = NS/GBA_CPU_CLOCK,
    frame_clock = GBA_CPU_CLOCK/60,         /*LCD刷新所用的CPU时钟*/
    hblank_clock = GBA_CPU_CLOCK/60/227,    /*每帧每扫描线所用CPU速度*/
    frame_Hz_mul1024 = ( /*1024秒绘制的整数帧数*/
        (GBA_CPU_CLOCK*0x10)/
        //     16 32 64 128 256 512 1024
        (280896  / 2/ 2/  2/  2/  2/   2)
    ),
};

#define REG_SETXGBA(reg,xgba)   \
    *((void**)&((reg)[0x60])) = (xgba)

#define REG_GETXGBA(reg)   \
    *((void**)&((reg)[0x60]))


extern int xgba_init(xgba_t*gba);
extern int xgba_loadrom(xgba_t*gba,const uint8_t*data);
extern int xgba_loadrom_free(xgba_t*gba,uint8_t*data,void (*_free)(void*data));
extern int xgba_loadbios(xgba_t*gba,const uint8_t*bios_data);

extern void xgba_clean(xgba_t*gba);
extern int xgba_close(xgba_t*gba);

extern int xgba_loop(xgba_t*gba);

#endif

